home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * File: sockets.c
- *
- * Author: Rhett "Jonzy" Jones jonzy@cc.utah.edu
- *
- * Date: March 15, 1993
- *
- * Modified: May 6, 1993, by Rhett "Jonzy" Jones.
- * Modifed ProcessRequest() to adhere to the gopher protocol
- * by sending error.host and -1 as the port if we encountered
- * an error. Done solely to prevent clients from crashing.
- *
- * May 18, 1993, by Rhett "Jonzy" Jones.
- * Added the #ifdef _POSIX_SOURCE in SendString() to prevent
- * core dumps under A/UX. Thank you hagberg@cumc.cornell.edu
- *
- * Description: Contains routines dealing with sockets and communicating
- * over the internet.
- *
- * Routines: void IP2Hostname(int sockfd,char *host,char *ip);
- * int SetUpReadNwriter(int theSocket);
- * void CloseReadNwriter(void);
- * int ContactHost(char* theHost, int thePort);
- * int SendString(char *s);
- * char *GetString(FILE *ptr);
- * void TooMuchTime4Read(void);
- * void ChildProcess(void);
- * int ListenerEstablished(int port);
- * int ProcessRequest(int sockfd);
- *
- * Bugs: No known bugs.
- *
- * Copyright: Copyright 1993, University of Utah Computer Center.
- * This source may be freely distributed as long as this copyright
- * notice remains intact, and is in no way used for any monetary
- * gain, by any institution, business, person, or persons.
- *
- ****************************************************************************/
-
- #include <setjmp.h>
- #include <signal.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <stdlib.h>
- #include <sys/socket.h>
- #include <sys/socketvar.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <sys/wait.h>
- #include <sys/param.h>
-
- #define READTIMEOUT (5 * 60)
- #define MAXLINE 512
- #define RECVSIZE 4096
-
- jmp_buf env;
-
- /* These are defined in "jughead.c". */
- extern int debug;
- extern FILE *wtPtr,
- *rdPtr;
- #define BUFFERSIZE 2048
- extern char buffer[BUFFERSIZE];
-
- /*****************************************************************************
- * IP2Hostname places the name of the host, as acquired from the IP
- * number, into 'host'. This way we can log the name of the host instead
- * of the IP number.
- ****************************************************************************/
- void IP2Hostname(sockfd,host,ip)
- int sockfd; /* Socket file descriptor. */
- char *host; /* The name of the host we are talking to. */
- char *ip; /* The hosts IP number. */
- { struct sockaddr_in sin; /* Info about the socket. */
- int len; /* The size of 'sin'. */
- struct hostent *hostEntry; /* Information about the host. */
-
- len = sizeof(sin);
- getpeername(sockfd,&sin,&len);
- strcpy(ip,inet_ntoa(sin.sin_addr));
- strcpy(host,inet_ntoa(sin.sin_addr));
-
- hostEntry = gethostbyaddr((char *)&sin.sin_addr,sizeof(sin.sin_addr.s_addr),AF_INET);
-
- if (hostEntry)
- (void)strcpy(host,hostEntry->h_name);
-
- } /* IP2Hostname */
-
- /*****************************************************************************
- * SetUpReadNwriter returns true if we can set up read and write pointers
- * to the socket 'theSocket'.
- ****************************************************************************/
- int SetUpReadNwriter(theSocket)
- int theSocket; /* The socket. */
- {
- /* See if we can open a file for writing. */
- if (!(wtPtr = fdopen(theSocket,"w")))
- {
- fprintf(stderr,"error: SetUpReadNwriter could not open socket file for writing.\n");
- return(0);
- }
-
- /* See if we can open a file for reading. */
- if (!(rdPtr = fdopen(theSocket,"r")))
- {
- fprintf(stderr,"error: SetUpReadNwriter could not open socket file for reading.\n");
- return(0);
- }
-
- return(1);
-
- } /* SetUpReadNwriter */
-
- /*****************************************************************************
- * CloseReadNwriter simply closes 'rdPtr' and 'wtPtr'.
- ****************************************************************************/
- void CloseReadNwriter()
- {
- fclose(wtPtr);
- fclose(rdPtr);
-
- } /* CloseReadNwriter */
-
- /*****************************************************************************
- * ContactHost returns true if we were able to get a connection to 'theHost'
- * out port 'thePort', and open the files 'wrPtr' and 'rdPtr' for reading and
- * and writing information to and from 'theHost' out 'thePort'. Otherwise
- * this routine returns false.
- ****************************************************************************/
- int ContactHost(theHost,thePort)
- char *theHost; /* The host to connect with. */
- int thePort; /* The port to use. */
- { int theSocket; /* The socket. */
- struct sockaddr_in scktRec; /* The socket address info. */
- struct hostent *theHostEntry; /* The host entry. */
-
- if (debug)
- fprintf(stderr,"ContactHost attempting a connection to: %s %d\n",theHost,thePort);
-
- /* See if we can get a socket. */
- if ((theSocket = socket(PF_INET,SOCK_STREAM,0)) < 0)
- {
- fprintf(stderr,"error: ContactHost cannot get the socket.\n");
- return(0);
- }
-
- /* Initialize our socket address information. */
- scktRec.sin_family = AF_INET;
- scktRec.sin_port = htons(thePort);
- if (theHostEntry = gethostbyname(theHost))
- bcopy(theHostEntry->h_addr,(char *)&scktRec.sin_addr.s_addr, 4);
- else
- {
- fprintf(stderr,"error: ContactHost found unknown host [%s].\n",theHost);
- return(0);
- }
-
- /* See if we can get a connection. */
- if (connect(theSocket,(struct sockaddr *)&scktRec,sizeof(scktRec)) < 0)
- {
- fprintf(stderr,"error: ContactHost cannot connect to [%s] via port [%d].\n",theHost,thePort);
- return(0);
- }
-
- if (!SetUpReadNwriter(theSocket))
- return(0);
-
- if (debug)
- fprintf(stderr,"ContactHost has established connection\n");
-
- return(1);
-
- } /* ContactHost */
-
- /*****************************************************************************
- * SendString returns true no matter what, but first writes the string 's' to
- * 'wtPtr' which is the machine we are talking to.
- ****************************************************************************/
- int SendString(s)
- char *s; /* The string we are sending to the machine. */
- {
- #ifdef _POSIX_SOURCE /* Prevent A/UX from dumping core. */
- fputs(s,wtPtr);
- #else
- fprintf(wtPtr,"%s",s);
- #endif
- fflush(wtPtr);
- return(1);
-
- } /* SendString */
-
- /*****************************************************************************
- * GetString returns a line of text from either the socket or file we are
- * reading from, which is pointed to by the 'ptr'. The string will contain at
- * most 'BUFFERSIZE' characters. For more information on the contents of the
- * string returned by this routine consult the man page on 'fgets'.
- ****************************************************************************/
- char *GetString(ptr)
- FILE *ptr; /* The file or socket we are reading from. */
- {
- return(fgets(buffer,BUFFERSIZE,ptr));
-
- } /* GetString */
-
- /*****************************************************************************
- * TooMuchTime4Read gets called only when the time period has elapsed when
- * waiting to read from our input..
- ****************************************************************************/
- void TooMuchTime4Read()
- {
- if (debug)
- fprintf(stderr,"In TooMuchTime4Read\n");
-
- longjmp(env,1);
-
- } /* TooMuchTime4Read */
-
- /*****************************************************************************
- * ChildProcess wait3() for a child's return code and status. This routine
- * is only called by the signal handler after receiving SIGCHLD.
- ****************************************************************************/
- void ChildProcess()
- { int status; /* Status of the child process. */
-
- while (wait3(&status,WNOHANG|WUNTRACED,NULL) > 0)
- ;
-
- } /* ChildProcess */
-
- /*****************************************************************************
- * ListenerEstablished returns -1 if we could NOT: create a socket, set up the socket
- * such that the address will be reused and will stick around for the client,
- * we can bind the socket to the port 'port', and we can set up to listen for
- * up to 5 connections out the port, a socket listening out port 'port'.
- * Otherwise we were able to do all of the above so we return the socket.
- ****************************************************************************/
- int ListenerEstablished(port)
- int port; /* The port to use. */
- { struct sockaddr_in sin; /* The socket information. */
- struct linger so_linger; /* The SO_LINGER info. */
- int so_reuseaddr, /* The SO_REUSEADDR info. */
- sckt, /* The socket to return. */
- error; /* Did we get an error? */
-
- if (debug)
- fprintf(stderr,"In ListenerEstablished\n");
-
- /* Initialize the variables. */
- so_reuseaddr = 1;
- error = so_linger.l_onoff = so_linger.l_linger = 0;
- bzero((char *)&sin,sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = htonl(INADDR_ANY);
- sin.sin_port = htons(port);
-
- /* Create a socket binding the same local address and make sure the other will still be around. */
- if ((sckt = socket(AF_INET,SOCK_STREAM,0)) >= 0)
- if (setsockopt(sckt,SOL_SOCKET,SO_REUSEADDR,(char *)&so_reuseaddr,sizeof(so_reuseaddr)) >= 0)
- if (setsockopt(sckt,SOL_SOCKET,SO_LINGER,(char *)&so_linger,sizeof(so_linger)) >= 0)
- if (bind(sckt,(struct sockaddr *)&sin,sizeof(sin)) >= 0)
- if (listen(sckt,5) >= 0)
- return(sckt);
- else
- error = fprintf(stderr,"ListenerEstablished: can't listen 5\n");
- else
- error = fprintf(stderr,"ListenerEstablished: can't bind\n");
- else
- error = fprintf(stderr,"ListenerEstablished: can't setsockopt SO_LINGER\n");
- else
- error = fprintf(stderr,"ListenerEstablished: can't setsockopt REUSEADDR!\n");
- else
- error = fprintf(stderr,"ListenerEstablished: can't socket\n");
-
- return(-error);
-
- } /* ListenerEstablished */
-
- /*****************************************************************************
- * ProcessRequest gets and processes a request from a port.
- ****************************************************************************/
- int ProcessRequest(sockfd)
- int sockfd; /* The socket file descriptor. */
- { char *inputline; /* The request to process. */
- int length; /* Length of the command line */
-
- if (!SetUpReadNwriter(sockfd))
- {
- fprintf(stderr,"error: ProcessRequest could not setup read and writters\n");
- return(0);
- }
-
- /* Set things up so we don't wait for ever waiting to get a request. */
- (void)signal(SIGALRM,TooMuchTime4Read);
- (void)alarm(READTIMEOUT);
-
- if (setjmp(env))
- {
- SendString("GetString: Timed out!\t\terror.host\t-1\r\n");
- exit(-1);
- }
-
- inputline = GetString(rdPtr);
- length = strlen(inputline);
-
- /* We got our request to deactivate the alarm. */
- (void)alarm(0);
- (void)signal(SIGALRM,SIG_IGN);
-
- if (length <= 0)
- {
- SendString("ProcessRequest: readline error\t\terror.host\t-1\r\n");
- close(sockfd);
- return(0);
- }
-
- RemoveCRLF(inputline);
-
- if (debug)
- fprintf(stderr,"ProcessRequest processing [%s]\n",inputline);
-
- PostPositions(sockfd,inputline);
- SendString(".\r\n");
- CloseReadNwriter();
- return(1);
-
- } /* ProcessRequest */
-
-